<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BConfig
 *
 * @author ID59C
 */
class BConfigManager {

    protected $paths = null;
    public $configFilePath = null;
    public $configFileName = 'config';
    protected $config = array();
    protected $basePath = 'application.application';
    public $owner = null;
    protected $arrayConfig = array();
    public $attributeNode = null;
    protected $fileConfigs = null;

    public function __construct($owner = NULL) {
        if ($owner != NULL)
            $this->owner = $owner;
        $this->initBasePath();
    }

    public function setConfigFilePath($configPath = NULL) {

        if ($configPath != NULL)
            $this->configFilePath = $configPath;
    }

    public function initBasePath() {
        $basePath = $this->getConfigValue('basePath');
        if ($basePath != NULL)
            $this->basePath = $basePath;

        return $this->basePath;
    }

    public function setConfigFileName($name) {
        if ($name != NULL)
            $this->configFileName = $name;
    }

    public function setOwner($owner) {
        $this->owner = $owner;
    }

    public function getConfigFile($data = NULL) {
        if ($this->configFilePath == NULL || $this->configFilePath == "application.application.config")
            $this->configFilePath = $this->basePath . '.' . 'config';
        return yii::getPathOfAlias($this->configFilePath) . '/' . $this->configFileName . ".php";
    }

    /**
     * save config file into datastore
     * @param type $configPath
     * @param type $configName
     */
    public function saveConfigsInConfigFile($configPath = NULL, $configName = NULL) {
        if ($configPath != NULL)
            $this->configFilePath = $configPath;
        if ($configName != NULL)
            $this->configFileName = $configName;

        $configFile = $this->configFilePath . '.' . $this->configFileName;
        $file = Yii::getPathOfAlias($configFile) . '.php';

        if (file_exists($file)) {
            $config = require($file);
            //$this->deleteConfigsInConfigFile();
            $this->addNestedConfig($config);
        }
    }

    protected function deleteConfigsInConfigFile($groupContext = null, $parentGroup = NULL) {
        if ($parentGroup == NULL)
            $parentGroup = $this->getRootNode();

        if ($groupContext == NULL) {
            $groupContext = array(
                'ownerType' => get_class($this->owner),
                'ownerId' => $this->owner->getId(),
                'configFile' => $this->getConfigFile(),
                'parent' => $parentGroup
            );
        }

        $groups = BConfigGroup::findAll($groupContext);

        foreach ($groups as $group) {
            $group->removeMembers();
            BGroup::delete($group);
        }
    }

    public function importConfigFromConfigFile($configFile = NULL, $data = NULL) {
        if ($configFile == NULL)
            $configFile = $this->getConfigFile();

        $configs = require $configFile;

        if ($configs != NULL) {
            $this->addNestedConfig($configs);
        }
    }

    /**
     * 
     * @param type $nestedConfig, array of config
     * @param type $parentConfig
     */
    public function addNestedConfig($nestedConfig, &$parentConfig = NULL) {
        //$configGroups = BConfigGroup::findAll(array());
        if ($parentConfig == NULL) {
            $parentConfig = $this->getRootNode();
        }

        $ownerId = $this->owner->getId();
        $configFile = $this->getConfigFile();

        $configContext = new BConfig();
        $configContext->ownerType = get_class($this->owner);
        $configContext->ownerId = $ownerId;
        $configContext->configFile = $configFile;

        $parentConfig->addConfigInArray($nestedConfig, $configContext);
    }

    //should return array that contain config information
    protected function parseConfig($configPath) {
        $this->configFilePath = $configPath;
        $configFile = $configPath . "." . $this->configFileName;

        $file = Yii::getPathOfAlias($configFile) . '.php';

        if (file_exists($file)) {
            $config = require($file);
            return $config;
        }

        return FALSE;
    }

    public function setConfig($config) {
        $this->config = $config;
    }

    /**
     * get config object
     * @param type $name, name can be nested name
     * @return mix BConfig or array
     */
    public function getConfig($name = NULL, $configContext = NULL, $parentConfig = NULL) {
        if ($parentConfig == NULL)
            $parentConfig = $this->getRootNode();
        if ($configContext instanceof BConfig)
            $configContext->name = $name;
        if (is_array($configContext))
            $configContext['name'] = $name;
        else {
            $configContext = $name;
        }
        $config = $parentConfig->getConfig($configContext);

        //then get config in config file
        if ($config == NULL || ($config instanceof BConfig && $config->getId() == NULL)) {
            $config = $this->getConfigNodeInConfigFile($name, $configContext);
        }
        return $config;
    }

    public function getConfigNodeInConfigFile($name, $data = NULL) {
        $arrayConfig = NULL;
        if ($this->owner instanceof BApp || $this->owner instanceof BlynApp)
            $arrayConfig = $this->getConfigInConfigFile();
        else {
            if ($this->owner instanceof BOperation) {
                $op = $this->owner;
                if($op instanceof BOperation){
                    $app = $op->getApp();
                }
                //$arrayConfig = Blyn::app()->getActiveApp()->getConfigManager()->getConfigInConfigFile();
                $arrayConfig = $app->getConfigManager()->getConfigInConfigFile();
                $name = 'appMeta.operations.' . $this->owner->getName() . '.' . $name;
            }
        }
        if (is_array($arrayConfig) && $arrayConfig != NULL) {
            $names = preg_split(BTreeEntity::Pattern_Delimiter, $name);
            $child = $arrayConfig;
            $i = 0;
            $count = count($names);
            foreach ($names as $oName) {
                if (is_array($child) && isset($child[$oName]) && $child[$oName] != NULL) {
                    $child = $child[$oName];
                    $i++;
                } else
                    break;
            }

            if ($i == $count)
                return $child;
        }
        return array();
    }

    public function getConfigValue($name = NULL, $configContext = null, $parentNode = null) {
        //first get config value from db config
        $config = $this->getConfig($name, $configContext, $parentNode);
        if ($config instanceof BConfig && $config->getValue() != NULL)
            return $config->getValue();

        if (is_array($config) && $config != NULL) {
            return reset($config);
        }

        return FALSE;
    }

    /**
     * 
     * @param type $data
     * @return \BConfig
     */
    public function getRootNode($data = NULL) {
        //return BConfig::getRoot();
        $root = BConfig::getRoot();
        $configContext = new BConfig();
        $configContext->name = 'config_root';
        $configContext->ownerType = get_class($this->owner);
        $configContext->ownerId = $this->owner->getId();
        $rootConfig = $root->getChild($configContext);
        if (!$rootConfig instanceof BConfig || $rootConfig->getId() == NULL)
            $rootConfig = $root->addChild($configContext);
        return $rootConfig;
    }

    /**
     * use this function to get all config under some config node
     * @param type $parentGroup
     * @param type $path
     * @return type
     */
    public function getConfigList($path = NULL, $configContext = NULL, $parentConfig = NULL) {

        $config = $this->getConfig($path, $configContext, $parentConfig);

        $configs = array();

        if ($config instanceof BConfig) {
            //$configContext->name = NULL;
            $configs = $config->getConfigList();
        }

        if (is_array($config) && $config != NULL) {
            foreach ($config as $key => $value) {
                $configs[$key] = $value;
            }
        }

        //add configs in config file into list
        $fileConfigs = $this->getConfigNodeInConfigFile($path);

        foreach ($fileConfigs as $name => $value) {
            if (is_string($name) && !isset($configs[$name]))
                $configs[$name] = $value;
        }

        return $configs;
    }

    public function getConfigListIntoStringList($path = NULL, $configContext = NULL, $parentConfig = NULL) {
        $configs = $this->getConfigList($path, $configContext, $parentConfig);

        foreach ($configs as $key => $config) {
            if ($config instanceof BConfig) {
                $name = $config->getName();
                $value = $config->getValue();
                if ($value != NULL)
                    $configs[$name] = $value;
                unset($configs[$key]);
            }
        }

        return $configs;
    }

    //if changed, return true, otherwise return false
    public function isConfigFileChanged($data = NULL) {

        $configScope = isset($data['scope']) ? $data['scope'] : NULL;

        if ($configScope == BContextObj::Scope_App) {

            $configFilePath = $this->getConfigFile();

            /**
              if (isset($this->configFileName) && isset($this->configFilePath))
              $configFileName = $this->configFilePath . "." . $this->configFileName;

              $configFilePath = yii::getPathOfAlias($this->configFilePath) . '\\' . $this->configFileName . ".php";
             * 
             */
            if (file_exists($configFilePath)) {

                $mdData = md5_file($configFilePath);

                $appId = $this->owner == NULL ? Blyn::app()->getActiveApp()->getId() : $this->owner->getId();

                $variableName = 'app_' . $appId . '.' . $this->configFilePath . '.' . $this->configFileName;

                $savedMdData = Blyn::app()->getContextVariable($variableName);

                //means config changed
                if ($savedMdData == null || $mdData != $savedMdData) {
                    //$mdData = md5_file($configFilePath);
                    Blyn::app()->addContextVariable($variableName, $mdData);
                    return TRUE;
                }
            }
        }

        return FALSE;
    }

    /**
     * add config into data store
     * @param type $name, can be nested name
     * @param type $value
     */
    public function addConfig($name, $value, $data = NULL, $parentConfig = NULL) {
        if (!$parentConfig instanceof BConfig)
            $parentConfig = $this->getRootNode();
        $config = new BConfig();
        $config->name = $name;
        $config->value = $value;
        $config->ownerId = $this->owner->getId();
        $config->ownerType = get_class($this);
        $parentConfig->addConfig($config);
    }

    /**
     * this function return config in array format
     * @param type $data
     * @return Array Description
     */
    public function getConfigInConfigFile($data = NULL) {

        //if ($this->fileConfigs != NULL)
        //return $this->fileConfigs;

        $file = $this->getConfigFile($data);
        if (file_exists($file)) {
            $config = require($file);
            //$this->arrayConfig = $config;
            //$this->fileConfigs = $config;
            return $config;
        }

        return FALSE;
    }

}

?>
